﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Data;
using System.Data.Linq;
using condortravel.operaciones.persistence.DataModel;
using condortravel.operaciones.persistence.Impl;
using LinqKit;
using condortravel.operaciones.core;
namespace condortravel.operaciones.persistence.Impl
{
    public abstract class  GenericDAO<E, PK> : DataContextTemplate, IGenericDAO<E, PK> where E : class
    {
        #region Attributes
        private ImpersonationBD.ImpersonationBD impersonationBD;
        #endregion

        #region Properties

        public bool IsImpersonate
        {
            get
            {
                return impersonationBD.IsImpersonate;
            }

        }

        public  Impersonation Impersonation
        {
            get{

               // if (!impersonationBD.IsImpersonate())
               //    throw new Exception("It does  not have impersonation");
                return impersonationBD.Impersonation;
            }
            
        }
        public ImpersonationBD.ImpersonationBD ImpersonationBD
        {
            set {
                impersonationBD = value;
            }
        
        }
        #endregion

        #region Constructor

        public GenericDAO()
        {
            
        }

        #endregion

        #region Overrides
        
        //public void SubmitChanges()
        //{
        //    using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
        //    {
        //        if (IsImpersonate)
        //        {
        //            if (!imp.ImpersonateUser())
        //            {
        //                throw new Exception("The Impersonate has failed");
        //            }

        //        }
        //        this.Context.SubmitChanges();
        //    }
    //}
        
        #endregion

        #region IGenericDAO<E,PK> Members

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityList"></param>
        /// <returns></returns>
        public void add(List<E> entityList)
        {
            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }
                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {
                    dataContext.GetTable<E>().InsertAllOnSubmit<E>(entityList);
                    dataContext.SubmitChanges();
                }
               
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public E add(E entity)
        {
            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }
                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {                    
                    dataContext.GetTable<E>().InsertOnSubmit(entity);
                    dataContext.SubmitChanges();
                }
                
                
                return entity;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public abstract E update(E entity);
        
        //    throw new NotImplementedException();
            //using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            //{
            //    if (IsImpersonate)
            //    {
            //        if (!imp.ImpersonateUser())
            //        {
            //            throw new Exception("The Impersonate has failed");
            //        }

            //    }
            //    using (DataContext dataContext = new DataContext(this.Context.Connection))
            //    {
            //        dataContext.SubmitChanges();
            //        return entity;
            //    }
            //}
      //  }

        public abstract E getByID(PK id);
        
        //public E getByID(PK id)
        //{
        //    var itemParameter = Expression.Parameter(typeof(E), "item");

        //    var whereExpression = Expression.Lambda<Func<E, bool>>
        //        (
        //            Expression.Equal(
        //                Expression.Property(
        //                    itemParameter,
        //                    typeof(E).GetPrimaryKey().Name
        //                ),
        //                Expression.Constant(id)
        //            ),<
        //            new ParameterExpression[] { itemParameter }
        //        );

        //    return this.Context.GetTable<E>().Where(whereExpression).Single();
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        public void delete(Expression<Func<E, bool>> Where)
        {
            
            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }
                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {
                    List<E> list = (from p in dataContext.GetTable<E>()
                                    select p)
                          .Where(Where).ToList<E>();
                    dataContext.GetTable<E>().DeleteAllOnSubmit<E>(list);
                    dataContext.SubmitChanges();
                    //dataContext.GetTable<E>().Attach(entity);
                    //dataContext.GetTable<E>().DeleteOnSubmit(entity);
                    //dataContext.SubmitChanges();
                }
               
            }
        }
        public abstract void delete(PK pk);
        //{

            //throw new NotImplementedException();
            
            //using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            //{
            //    if (IsImpersonate)
            //    {
            //        if (!imp.ImpersonateUser())
            //        {
            //            throw new Exception("The Impersonate has failed");
            //        }

            //    }
            //    using (DataContext dataContext = new DataContext(this.Context.Connection))
            //    {
            //        E entity = getByID(pk);                    
            //        dataContext.GetTable<E>().DeleteOnSubmit(entity);
            //        dataContext.SubmitChanges();
            //    }

            //}
          
        //}
        /// <summary>
        /// Get all the list of the entity
        /// </summary>
        /// <returns></returns>
        public List<E> getListAll()
        {
            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }
                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {
                    return (from p in dataContext.GetTable<E>()
                            select p).ToList<E>();
                }
            }
 
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pageSize"></param>
        /// <param name="pageNumber"></param>
        /// <returns></returns>
        public List<E> getListAll(int pageSize, int pageNumber)
        {
            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }
                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {
                    List<E> ret = (from p in dataContext.GetTable<E>()
                                   select p)
                            .Take<E>(pageSize)
                            .Skip<E>(pageNumber * pageSize)
                            .ToList<E>();
                    return ret;
                }
            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Where"></param>
        /// <returns></returns>
        public List<E> getList(int pageSize, int pageNumber,Expression<Func<E, bool>> Where)
        {

            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }
                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {
                    List<E> list = (from p in dataContext.GetTable<E>()
                                    select p)
                            .Where(Where)
                            .Take<E>(pageSize)
                            .Skip<E>(pageNumber * pageSize)
                            .ToList<E>();
                    //this.Context.Refresh(RefreshMode.OverwriteCurrentValues);
                    return list;
                }
            }
        }


        /// <summary>
        /// Get the list of the entity based criteria
        /// </summary>
        /// <param name="Where">criteria</param>
        /// <returns></returns>
        public List<E> getList(Expression<Func<E, bool>> Where)
        {
            
            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }

                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {
                    List<E> list = (from p in dataContext.GetTable<E>()
                                    select p)
                            .Where(Where).ToList<E>();
                    try
                    {
                        dataContext.Refresh(RefreshMode.OverwriteCurrentValues, list);
                    }
                    catch (Exception exc) { }
                    return list;
                }
               
               
            }
        }
        public List<E> getListWithoutImp(Expression<Func<E, bool>> Where)
        {
            using (DataContext dataContext = new DataContext(this.ConnectionString))
            {
                return (from p in dataContext.GetTable<E>()
                        select p)
                        .Where(Where).ToList<E>();
            }
          
        }

        public void executeSQL(string sql)
        {
            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }
                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {                    
                    dataContext.ExecuteCommand(sql);
                }
            }
        }

        #endregion           
        
        #region Public methods

        public void truncateRelatedTable(string tableName)
        {
            this.executeSQL(string.Format("truncate table {0}", tableName));
        }

        public DataContext getInstanceDataContextFactory()
        {
            return DataContextFactory.getDataContextInstance(this.Context);
            
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public bool checkIfExistTable(string tableName)
        {

            using (ImpersonationHelper imp = new ImpersonationHelper(this.Impersonation.User, this.Impersonation.Domain, this.Impersonation.Password))
            {
                if (IsImpersonate)
                {
                    if (!imp.ImpersonateUser())
                    {
                        throw new Exception("The Impersonate has failed");
                    }

                }
                using (DataContext dataContext = new DataContext(this.ConnectionString))
                {
                    string check = string.Format("SELECT so.name FROM  sysobjects so, sysindexes si  WHERE so.xtype = 'U' AND si.id = OBJECT_ID(so.name)  and so.name='{0}' GROUP BY  so.name", tableName);
                    IEnumerable<String> verify = dataContext.ExecuteQuery<String>(check);
                    int filenumber = verify.Count<String>();
                    return (filenumber > 0);
                }
            }
        }


    }
    public static class SoundexExtensions
    {
        public static int SimilarityTo(this string first, string second)
        {
            throw new NotImplementedException();
        }
    }
        #endregion


}
